<template>
  <div class="hud-container">
    <div class="opening-animation" ref="openingAnimation"></div>
    <span class="hud-trace-container" v-show="showHud">
      <div class="hud-trace-container-padding top"></div>
      <div class="hud-trace">
        <div class="hud-trace-padding" ref="hudTracePadding"></div>
        <div>
          <div class="hud-trace-cursor">
            <span class="hud-trace-cursor-left" @click="scrollToCursor()">
              <span class="hud-angle left top trace-cursor"></span>
              <span class="hud-angle right top trace-cursor"></span>
              <div class="hud-trace-cursor-val">{{ cursorValFormat }}</div>
              <span class="hud-angle left bottom trace-cursor"></span>
              <span class="hud-angle right bottom trace-cursor"></span></span
            ><span class="hud-trace-cursor-right"></span>
          </div>
        </div>
      </div>
      <div class="hud-trace-container-padding bottom"></div>
    </span>
    <span class="hud" ref="hud" v-show="showHud">
      <div class="hud-border top">
        <div class="hud-angle left top"></div>
        <div class="hud-angle right top"></div>
        <div class="hud-border shadow top">
          <div class="hud-angle shadow left top"></div>
          <div class="hud-angle shadow right top"></div>
        </div>
      </div>
      <!-- 动态加载的内容 start -->
      <div class="hud-body" ref="hudBody">
        <DynamicComponent
          ref="hudBodyContent"
          :componentName="componentName"
          :importPath="importPath"
          :componentObj="componentObj"
        ></DynamicComponent>
      </div>
      <!-- 动态加载的内容 end -->
      <div class="hud-border bottom">
        <div class="hud-angle left bottom"></div>
        <div class="hud-angle right bottom"></div>
        <div class="hud-border shadow bottom">
          <div class="hud-angle shadow left bottom"></div>
          <div class="hud-angle shadow right bottom"></div>
        </div>
      </div>
    </span>
  </div>
</template>

<script>
import DynamicComponent from './DynamicComponent.vue'
import gsap from 'gsap'
export default {
  name: 'Hud',
  components: { DynamicComponent },
  props: {
    componentName: String,
    importPath: String,
    componentObj: Object
  },
  data () {
    return {
      showHud: true,
      scrollAnimationReady: true,
      cursorVal: 0,
      cursorAbsoluteTop: -1
    }
  },
  computed: {
    cursorValFormat () {
      return this.cursorVal.toFixed(2)
    }
  },
  created () {},
  mounted () {
    // 窗口重绘事件
    window.addEventListener('resize', this.updateCursorHightFrequency, true)
    // 编辑区的滚动事件
    this.$refs.hudBody.addEventListener(
      'scroll',
      this.updateCursorHightFrequency,
      true
    )
    // 光标选区修改事件
    document.addEventListener(
      'selectionchange',
      this.selectionChangeHandle,
      true
    )
    // 开场动画
    // this.openingAnimation()
  },
  destroyed () {
    window.removeEventListener('resize', this.updateCursorHightFrequency, true)
    document.removeEventListener(
      'scroll',
      this.updateCursorHightFrequency,
      true
    )
    document.removeEventListener(
      'selectionchange',
      this.selectionChangeHandle,
      true
    )
  },
  methods: {
    // 开场动画
    openingAnimation () {
      let self = this
      self.showHud = false
      gsap
        .timeline()
        .delay(0.6)
        // 闪烁动画
        .to(this.$refs.openingAnimation, {
          startAt: { display: 'block' },
          display: 'none',
          repeat: 2,
          duration: 0.4,
          repeatDelay: 0.4
        })
        // 展开动画
        .to(this.$refs.hud, {
          startAt: { y: '50vh', height: 0 },
          y: '0vh',
          height: '100%',
          duration: 0.4,
          onStart () {
            self.showHud = true
            // 游标动画
            gsap.to(self.$data, {
              startAt: { cursorVal: 1 },
              duration: 0.6,
              cursorVal: 0
            })
          }
        })
    },
    updateCursorHightFrequency () {
      if (this.cursorAbsoluteTop >= 0 && this.scrollAnimationReady) {
        this.scrollAnimationReady = false
        window.requestAnimationFrame(() => {
          // 更新游标
          this.updateCursor(this.cursorAbsoluteTop, this.$refs.hudBody)
          this.$emit('updateCursor', this.cursorAbsoluteTop)
          this.scrollAnimationReady = true
        })
      }
    },
    selectionChangeHandle () {
      let selection = window.getSelection()
      let offset = selection.focusOffset
      let textEl = selection.focusNode
      if (!this.$refs.hudBody.contains(textEl)) {
        return
      }
      let textContent = textEl.nodeValue
      let probeEl = document.createElement('span')
      probeEl.innerHTML = '&zwnj;'
      // 插入定位用的节点
      if (offset === 0) {
        textEl.before(probeEl)
      } else if (offset === textContent.length) {
        textEl.after(probeEl)
      } else {
        textEl.splitText(offset)
        textEl.after(probeEl)
      }
      // 更新游标
      this.updateCursorByProbe(probeEl)
      // 删除节点
      textEl.parentElement.removeChild(probeEl)
    },
    updateCursorByProbe (probeEl) {
      // 获取主体的高度
      let scrollEl = this.$refs.hudBody
      let scrollElPosInfo = scrollEl.getBoundingClientRect()
      // 探针的位置信息
      let probeElPosInfo = probeEl.getBoundingClientRect()
      let probeRelativeTop =
        (probeElPosInfo.top + probeElPosInfo.bottom) / 2 - scrollElPosInfo.top
      let probeAbsoluteTop = scrollEl.scrollTop + probeRelativeTop
      // 更新游标
      this.updateCursor(probeAbsoluteTop, this.$refs.hudBody)
    },
    // 更新cursorVal的值
    updateCursorVal (probeAbsoluteTop, scrollEl) {
      this.cursorAbsoluteTop = probeAbsoluteTop
      // 以滚动窗口中间为原点,cursorVal由光标到原点的距离,除以原点到滚动页面顶部或底部的距离得到,原点以下为负
      let observerAbsoluteTop = scrollEl.clientHeight / 2 + scrollEl.scrollTop
      let vector = observerAbsoluteTop - probeAbsoluteTop
      let cursorVal =
        vector /
        (vector > 0
          ? observerAbsoluteTop
          : scrollEl.scrollHeight - observerAbsoluteTop)
      gsap.to(this.$data, {
        overwrite: true,
        cursorVal: cursorVal
      })
    },
    // 游标的相关操作
    updateCursor (cursorAbsoluteTop, scrollEl) {
      // 更新游标中的值
      this.updateCursorVal(cursorAbsoluteTop, scrollEl)
      // 移动游标到指定高度
      let cursorRelativePctTop =
        ((cursorAbsoluteTop - scrollEl.scrollTop) / scrollEl.clientHeight) * 100
      cursorRelativePctTop =
        cursorRelativePctTop < 0
          ? 0
          : cursorRelativePctTop > 100
            ? 100
            : cursorRelativePctTop
      gsap.to(this.$refs.hudTracePadding, {
        overwrite: true,
        height: cursorRelativePctTop + '%'
      })
    },
    // 滚动到光标位置
    scrollToCursor (observerAbsoluteTop) {
      observerAbsoluteTop =
        observerAbsoluteTop || this.$refs.hud.clientHeight / 2
      let scrollTo = this.cursorAbsoluteTop - observerAbsoluteTop
      scrollTo = scrollTo < 0 ? 0 : scrollTo
      gsap.to(this.$refs.hudBody, {
        duration: 0.5,
        scrollTop: scrollTo
      })
    }
  }
}
</script>

<style scoped>
.opening-animation {
  display: none;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  width: 20px;
  height: 30px;
  background-color: rgba(0, 0, 0, 0.4);
}
.opening-animation::after {
  content: '';
  position: absolute;
  transform: translate(5px, 4px);
  width: 20px;
  height: 30px;
  background-color: rgba(0, 0, 0, 0.1);
}
.hud-container {
  position: relative;
  width: 100%;
  height: 100%;
}
.hud-trace-container {
  position: absolute;
  display: inline-flex;
  flex-direction: column;
  width: 0px;
  height: 100%;
}
.hud-trace-container-padding {
  height: 0px;
}
.hud-trace {
  flex: auto;
  height: 100%;
  width: 0px;
}
.hud-trace::before {
  content: '';
  position: absolute;
  transform: translate(9px, 0);
  top: 0;
  bottom: 0;
  margin: auto;
  display: block;
  width: 2.5px;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.06);
}
.hud-trace::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  display: block;
  width: 20px;
  height: 2.5px;
  background-color: rgba(0, 0, 0, 0.06);
}
.hud-trace-padding {
  height: 50%;
}
.hud-trace-cursor {
  position: absolute;
  right: 0;
  transform: translate(0, -50%);
  width: 75px;
  height: 30px;
}
.hud-trace-cursor-left {
  cursor: pointer;
  position: relative;
  display: inline-block;
  width: 50px;
  height: 30px;
}
.hud-trace-cursor-left::before {
  content: '';
  position: absolute;
  display: block;
  top: 0;
  width: 48px;
  height: 28px;
  border: 1px solid rgba(251, 193, 5, 0.1);
}
.hud-trace-cursor-val {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  text-align: center;
  height: 1em;
  line-height: 1;
  color: rgb(251, 193, 5);
}
.hud-trace-cursor-right {
  display: inline-block;
  margin-left: 5px;
  width: 0;
  height: 0;
  border-top: 15px solid transparent;
  border-left: 15px solid rgba(251, 193, 5, 0.12);
  border-bottom: 15px solid transparent;
}
.hud {
  position: relative;
  float: right;
  display: flex;
  flex-direction: column;
  word-wrap: break-word;
  width: 100%;
  height: 100%;
}
.hud-body {
  flex: 1;
  margin: 0px 14px 0px 30px;
  overflow-y: scroll;
}
.hud-body::-webkit-scrollbar {
  width: 1px;
}
.hud-body::-webkit-scrollbar-thumb {
  width: 1px;
  background-color: rgba(0, 0, 0, 0.04);
}
.hud-border {
  position: relative;
  height: 1.5px;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.06);
}
.hud-angle {
  position: absolute;
  display: inline-block;
  border: 1px solid #b2b2b2;
  width: 17px;
  height: 17px;
}
.hud-angle.left.top {
  border-right-width: 0px;
  border-bottom-width: 0px;
}
.hud-angle.right.top {
  right: 0;
  border-left-width: 0px;
  border-bottom-width: 0px;
}
.hud-angle.left.bottom {
  bottom: 0px;
  border-right-width: 0px;
  border-top-width: 0px;
}
.hud-angle.right.bottom {
  right: 0;
  bottom: 0px;
  border-left-width: 0px;
  border-top-width: 0px;
}
.shadow {
  z-index: -1;
  position: absolute;
  border-color: rgba(0, 0, 0, 0.06);
}
.hud-border.shadow {
  transform: translate(8px, 10px);
  width: 100%;
  height: 0;
}
.hud-border.shadow.bottom {
  transform: translate(8px, -7px);
}
.trace-cursor {
  border: 1px solid rgba(251, 193, 5, 0.7);
  width: 5px;
  height: 5px;
}
/* .hud-content-length-view {
  position: absolute;
  bottom: 0;
  margin-left: 10px;
  margin-bottom: 13px;
  width: 80px;
  height: 30px;
  border: 10px solid rgb(255, 255, 255);
  background-color: #f0f0f0;
} */
</style>
